package com.yiyuan.app.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.cloudauth20190307.models.Id2MetaVerifyRequest;
import com.aliyun.cloudauth20190307.models.Id2MetaVerifyResponse;
import com.aliyun.cloudauth20190307.models.Id2MetaVerifyResponseBody;
import com.guaike.core.entity.context.ContextHolder;
import com.guaike.core.entity.result.Result;
import com.guaike.core.redis.context.ApiContext;
import com.guaike.core.utils.ListUtil;
import com.guaike.core.utils.UUIDUtil;
import com.yiyuan.app.config.AliAccessKeyProperties;
import com.yiyuan.app.dao.OAppVersionDAO;
import com.yiyuan.app.dao.OBannerDAO;
import com.yiyuan.app.dao.UAppUserDAO;
import com.yiyuan.app.dao.UAppUserEquityDAO;
import com.yiyuan.app.entity.enums.BannerTypeEnum;
import com.yiyuan.app.entity.enums.SexEnum;
import com.yiyuan.app.entity.enums.UserStatusEnum;
import com.yiyuan.app.entity.param.AuthRealNameDTO;
import com.yiyuan.app.entity.param.BindWxDTO;
import com.yiyuan.app.entity.param.IosLoginDTO;
import com.yiyuan.app.entity.param.WxLoginDTO;
import com.yiyuan.app.entity.po.OAppVersionPO;
import com.yiyuan.app.entity.po.OBannerPO;
import com.yiyuan.app.entity.po.UAppUserEquityPO;
import com.yiyuan.app.entity.po.UAppUserPO;
import com.yiyuan.app.entity.result.*;
import com.yiyuan.app.service.LoginService;
import com.yiyuan.app.utils.IOSTokenUtils;
import com.yiyuan.app.utils.Id2MetaVerifyUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Random;

@Slf4j
@Service
@AllArgsConstructor
public class LoginServiceImpl implements LoginService {

    private final static List<String> avatarList = Arrays.asList("https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image1.png", "https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image2.png", "https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image3.png"
            , "https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image4.png", "https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image5.png", "https://sscw-resource.oss-cn-hangzhou.aliyuncs.com/avatar/image6.png");

    private final WxMpService wxService;
    private final UAppUserDAO uAppUserDAO;
    private final AliAccessKeyProperties aliAccessKeyProperties;
    private final OBannerDAO oBannerDAO;
    private final OAppVersionDAO oAppVersionDAO;
    private final UAppUserEquityDAO uAppUserEquityDAO;

    @Override
    @Transactional
    public Result<AppUserVO> wxLogin(WxLoginDTO param) throws WxErrorException {
        if (!this.wxService.switchover(param.getAppId())) {
            return Result.failure().message(String.format("未找到对应appId=[%s]的配置，请核实！", param.getAppId())).build();
        }
        WxOAuth2AccessToken wxAccessToken = wxService.getOAuth2Service().getAccessToken(param.getCode());
        WxOAuth2UserInfo wxUser = wxService.getOAuth2Service().getUserInfo(wxAccessToken, null);
        UAppUserPO uAppUserPO = uAppUserDAO.findNoCancelWx(wxUser.getOpenid());
        AppUserVO vo = new AppUserVO();
        AppUser appUser = new AppUser();
        if (Objects.nonNull(uAppUserPO)) {
            if (uAppUserPO.getStatus().equals(UserStatusEnum.ban.getCode())) {
                return Result.failure().message("该账号已被封号，不能登录").build();
            }
            BeanUtils.copyProperties(uAppUserPO, appUser);
            appUser.setSessionKey(wxAccessToken.getAccessToken());
            appUser.setUserId(uAppUserPO.getId());
            String accessToken = ApiContext.setCurrentUser(appUser, ContextHolder.getClientId());
            uAppUserPO.setAccessToken(accessToken);
            uAppUserPO.setSessionKey(wxAccessToken.getAccessToken());
            appUser.setAccessToken(accessToken);
            vo.setUserId(uAppUserPO.getId());
            vo.setAccessToken(accessToken);
            if (!uAppUserPO.getIsCertify()) {
                vo.setAuthRealName(Boolean.TRUE);
            }
            uAppUserDAO.updateById(uAppUserPO);
        } else {
            uAppUserPO = new UAppUserPO();
            Random random = new Random();
            int number = 1000 + random.nextInt(10000);
            uAppUserPO.setNickname("squirrel" + number);
            int randomNumber = random.nextInt(7);
            uAppUserPO.setAvatarurl(avatarList.get(randomNumber));
            String itemVersion = UUIDUtil.createItemVersion();
            uAppUserPO.setInviterCode(itemVersion.substring(itemVersion.length() - 8));
            uAppUserPO.setOpenid(wxUser.getOpenid());
            uAppUserPO.setUnionid(wxUser.getUnionId());
            uAppUserPO.setCountry(wxUser.getCountry());
            uAppUserPO.setProvince(wxUser.getProvince());
            uAppUserPO.setCity(wxUser.getCity());
            SexEnum sexEnum = SexEnum.getByCode(wxUser.getSex());
            uAppUserPO.setGender(Objects.nonNull(sexEnum) ? sexEnum.getDesc() : "其他");
            uAppUserPO.setSessionKey(wxAccessToken.getAccessToken());
            uAppUserDAO.save(uAppUserPO);
            BeanUtils.copyProperties(uAppUserPO, appUser);
            appUser.setUserId(uAppUserPO.getId());
            String accessToken = ApiContext.setCurrentUser(appUser, ContextHolder.getClientId());
            appUser.setAccessToken(accessToken);
            uAppUserPO.setAccessToken(accessToken);
            uAppUserDAO.updateById(uAppUserPO);
            appUser.setUserId(uAppUserPO.getId());
            UAppUserEquityPO equityPO = new UAppUserEquityPO();
            equityPO.setUserId(uAppUserPO.getId());
            equityPO.setManageMoney(new BigDecimal(0));
            equityPO.setVipGrade(0);
            equityPO.setRechargeMoney(new BigDecimal(0));
            equityPO.setPinecone(0);
            equityPO.setPineNut(0);
            equityPO.setForbidLookThirty(0);
            equityPO.setLockFifteen(0);
            equityPO.setLockThirty(0);
            equityPO.setLockSixty(0);
            uAppUserEquityDAO.save(equityPO);
            vo.setUserId(uAppUserPO.getId());
            vo.setAccessToken(accessToken);
            vo.setAuthRealName(Boolean.TRUE);
        }
        return Result.success().data(vo).build();
    }

    @Override
    public Result<LoginUserVO> iosLogin(IosLoginDTO param) {
        // 解码后的消息体
        JSONObject preloadObj = IOSTokenUtils.parserIdentityToken(param.getIdentityToken());
        Boolean success = IOSTokenUtils.verifyExc(param.getIdentityToken(), preloadObj);
        if (!success) {
            return Result.failure().message("identityToken验证失败").build();
        }
        String iosSub = preloadObj.getString("sub");
        UAppUserPO uAppUserPO = uAppUserDAO.findNoCancelIos(iosSub);
        LoginUserVO userVO = new LoginUserVO();
        AppUser appUser = new AppUser();
        if (Objects.nonNull(uAppUserPO)) {
            if (uAppUserPO.getStatus().equals(UserStatusEnum.ban.getCode())) {
                return Result.failure().message("该账号已被封号，不能登录").build();
            }
            BeanUtils.copyProperties(uAppUserPO, appUser);
            appUser.setUserId(uAppUserPO.getId());
            String accessToken = ApiContext.setCurrentUser(appUser, ContextHolder.getClientId());
            uAppUserPO.setAccessToken(accessToken);
            userVO.setWxAuth(Boolean.FALSE);
            userVO.setUserId(uAppUserPO.getId());
            userVO.setAccessToken(accessToken);
            uAppUserDAO.updateById(uAppUserPO);
            if (!uAppUserPO.getIsCertify()) {
                userVO.setAuthRealName(Boolean.TRUE);
            }
        } else {
            uAppUserPO = new UAppUserPO();
            Random random = new Random();
            int number = 1000 + random.nextInt(10000);
            uAppUserPO.setNickname("squirrel" + number);
            int randomNumber = random.nextInt(7);
            uAppUserPO.setAvatarurl(avatarList.get(randomNumber));
            uAppUserPO.setIosSub(iosSub);
            String itemVersion = UUIDUtil.createItemVersion();
            uAppUserPO.setInviterCode(itemVersion.substring(itemVersion.length() - 8));
            uAppUserDAO.save(uAppUserPO);
            BeanUtils.copyProperties(uAppUserPO, appUser);
            appUser.setUserId(uAppUserPO.getId());
            String accessToken = ApiContext.setCurrentUser(appUser, ContextHolder.getClientId());
            userVO.setWxAuth(Boolean.TRUE);
            userVO.setAccessToken(accessToken);
            uAppUserPO.setAccessToken(accessToken);
            uAppUserDAO.updateById(uAppUserPO);
            userVO.setUserId(uAppUserPO.getId());
            UAppUserEquityPO equityPO = new UAppUserEquityPO();
            equityPO.setUserId(uAppUserPO.getId());
            equityPO.setManageMoney(new BigDecimal(0));
            equityPO.setVipGrade(0);
            equityPO.setRechargeMoney(new BigDecimal(0));
            equityPO.setPinecone(0);
            equityPO.setPineNut(0);
            equityPO.setForbidLookThirty(0);
            equityPO.setLockFifteen(0);
            equityPO.setLockThirty(0);
            equityPO.setLockSixty(0);
            uAppUserEquityDAO.save(equityPO);
            userVO.setAuthRealName(Boolean.TRUE);
        }
        return Result.success().data(userVO).build();
    }

    @Override
    @Transactional
    public Result<Boolean> bindWx(BindWxDTO param) throws WxErrorException {
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserPO uAppUserPO = uAppUserDAO.findById(currentUser.getUserId());
        if (StringUtils.isNotBlank(uAppUserPO.getOpenid())
                || StringUtils.isNotBlank(uAppUserPO.getUnionid())) {
            return Result.failure().message("当前用户已绑定过微信").build();
        }
        if (uAppUserPO.getCreateTime().plusMinutes(5L).isBefore(LocalDateTime.now())) {
            return Result.failure().message("当前用户超过可绑定微信时间").build();
        }
        if (!this.wxService.switchover(param.getAppId())) {
            return Result.failure().message(String.format("未找到对应appId=[%s]的配置，请核实！", param.getAppId())).build();
        }
        WxOAuth2AccessToken wxAccessToken = wxService.getOAuth2Service().getAccessToken(param.getCode());
        WxOAuth2UserInfo wxUser = wxService.getOAuth2Service().getUserInfo(wxAccessToken, null);
        UAppUserPO userPO = uAppUserDAO.findNoCancelWx(wxUser.getOpenid());
        if (Objects.nonNull(userPO)) {
            return Result.failure().message("该微信已存在用户，请绑定其他微信").build();
        }
        uAppUserPO.setOpenid(wxUser.getOpenid());
        uAppUserPO.setUnionid(wxUser.getUnionId());
        uAppUserPO.setCountry(wxUser.getCountry());
        uAppUserPO.setProvince(wxUser.getProvince());
        uAppUserPO.setCity(wxUser.getCity());
        SexEnum sexEnum = SexEnum.getByCode(wxUser.getSex());
        uAppUserPO.setGender(Objects.nonNull(sexEnum) ? sexEnum.getDesc() : "其他");
        uAppUserPO.setSessionKey(wxAccessToken.getAccessToken());
        uAppUserDAO.updateById(uAppUserPO);
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> authRealName(AuthRealNameDTO param) {
        AppUser currentUser = ApiContext.getCurrentUser();
        UAppUserPO uAppUserPO = uAppUserDAO.findById(currentUser.getUserId());
        if (uAppUserPO.getIsCertify()) {
            return Result.failure().message("当前用户已经实名").build();
        }
        Long count = uAppUserDAO.findCount(UAppUserPO::getIdCard, param.getIdCard());
        if (count > 0) {
            return Result.failure().message("该实名信息已被占用").build();
        }
        Id2MetaVerifyRequest request = new Id2MetaVerifyRequest();
        request.setParamType("normal");
        request.setUserName(param.getRealName());
        request.setIdentifyNum(param.getIdCard());
        Id2MetaVerifyResponse response = Id2MetaVerifyUtils.id2MetaVerifyAutoRoute(request, aliAccessKeyProperties);
        Id2MetaVerifyResponseBody.Id2MetaVerifyResponseBodyResultObject resultObject = response.getBody().getResultObject();
        if (Objects.isNull(resultObject)) {
            return Result.failure().message("实名认证失败").build();
        }
        if ("1".equals(resultObject.getBizCode())) {
            uAppUserPO.setIsCertify(Boolean.TRUE);
            uAppUserPO.setRealName(param.getRealName());
            uAppUserPO.setIdCard(param.getIdCard());
            uAppUserDAO.updateById(uAppUserPO);
            return Result.success().data(Boolean.TRUE).build();
        } else if ("2".equals(resultObject.getBizCode())) {
            return Result.failure().message("校验不⼀致").build();
        } else {
            return Result.failure().message("查⽆记录").build();
        }
    }

    @Override
    public Result<Boolean> logout() {
        ApiContext.removeCurrentUser();
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<List<ImageVO>> startPage() {
        List<OBannerPO> pos = oBannerDAO.findList(OBannerPO::getBannerType, BannerTypeEnum.start_page.getCode(), OBannerPO::getId);
        List<ImageVO> vos = ListUtil.copyList(pos, ImageVO.class);
        return Result.success().data(vos).build();
    }

    @Override
    public Result<VersionVO> checkAppUpdate() {
        String clientId = ContextHolder.getClientId();
        String clientVersion = ContextHolder.getClientVersion();
        VersionVO result = new VersionVO();
        OAppVersionPO latestVersion = oAppVersionDAO.findLatestVersion(clientId);
        if (Objects.nonNull(latestVersion) && clientVersion.compareTo(latestVersion.getVersionNo()) < 0) {
            result.setIsUpdate(Boolean.TRUE);
            result.setVersion(latestVersion.getVersionNo());
            result.setDownLoadUrl(latestVersion.getUrl());
        }
        return Result.success().data(result).build();
    }

}
